package cn.thoughtworks.school.usercenter.services;

import cn.thoughtworks.school.usercenter.entities.*;
import cn.thoughtworks.school.usercenter.entities.commands.CreateUserOrganization;
import cn.thoughtworks.school.usercenter.entities.commands.CreateUsersCommand;
import cn.thoughtworks.school.usercenter.entities.vo.UserInfo;
import cn.thoughtworks.school.usercenter.exceptions.BusinessException;
import cn.thoughtworks.school.usercenter.feign.OrganizationCenterFeign;
import cn.thoughtworks.school.usercenter.repositories.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.joining;

@Service
public class UserService {
    @Autowired
    private UserRoleRepository userRoleRepository;
    @Autowired
    private SocialAccountRepository socialAccountRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserDetailRepository userDetailRepository;
    @Autowired
    private NodeBBUserRepository nodeBBUserRepository;
    @Autowired
    private OrganizationCenterFeign organizationCenterFeign;

    private final static Integer ORGANIZATION_ROLE = 5;

    public List<UserRole> findRoles() {
        return userRoleRepository.findAll();
    }

    public void deleteOrganizationUserRole(Long organizationId, Long userId, Integer role) {
        userRoleRepository.deleteByOrganizationIdAndUserIdAndRole(organizationId, userId, role);
    }

    public void addUserRole(UserRole userRole) {
        userRoleRepository.save(userRole);
    }

    public void deleteSocialAccountByUsername(String username) {
        socialAccountRepository.deleteSocialAccountByUsername(username);
    }

    public List<SocialAccount> findSocialAccountByUsername(String username) {
        return socialAccountRepository.findByUsername(username);
    }

    public Map findUserById(Long userId) throws BusinessException {
        User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException("当前用户不存在"));
        UserDetail detail = userDetailRepository.findById(userId).orElseThrow(() -> new BusinessException("当前用户详细不存在" + userId));
        List<UserRole> userRoleList = userRoleRepository.findByUserId(userId);
        userRoleList = filterByOrganizationAndTutor(userRoleList, detail.getCurrentOrganizationId());
        Map<String, Object> result = new HashMap();
        result.put("id", user.getId());
        result.put("email", user.getEmail());
        result.put("mobilePhone", user.getMobilePhone());
        result.put("userName", user.getUsername());

        if (detail != null) {
            result.put("userId", detail.getUserId());
            result.put("school", detail.getSchool());
            result.put("name", detail.getName());
            result.put("major", detail.getMajor());
            result.put("degree", detail.getDegree());
            result.put("gender", detail.getGender());
            result.put("schoolProvince", detail.getSchoolProvince());
            result.put("schoolCity", detail.getSchoolCity());
            result.put("entranceYear", detail.getEntranceYear());
            result.put("wechat", detail.getWechat());
            result.put("currentOrganizationId", detail.getCurrentOrganizationId());
            result.put("qq", detail.getQq());
        }

        if (userRoleList != null) {
            ArrayList<Integer> roles = new ArrayList<>();
            for (UserRole userRole : userRoleList) {
                roles.add(userRole.getRole());
            }
            result.put("roles", roles);
        }

        return result;
    }

    private List<UserRole> filterByOrganizationAndTutor(List<UserRole> userRoleList, Long currentOrganizationId) {
        Integer TUTOR_ROLE = 2;
        return userRoleList.stream().filter(userRole -> userRole.getOrganizationId().equals(currentOrganizationId) ||
            userRole.getRole().equals(TUTOR_ROLE)).collect(Collectors.toList());

    }

    public List<User> getUserByUsernameContainingOrEmailContaining(String query, Pageable topTen) {
        List<User> users = userRepository
            .getUserByUsernameContainingOrEmailContaining(query, query, topTen);
        users.forEach(User::hidePassword);
        return users;
    }

    public User findUsername(String username) {
        User user = userRepository.findByUsername(username);
        user.hidePassword();
        return user;
    }

    public User findByMobilePhone(String mobilePhone) {
        User user = userRepository.findByMobilePhone(mobilePhone);
        user.hidePassword();
        return user;
    }

    public List<User> findAllByIdIn(List<Long> idList) {
        List<User> users = userRepository.getAllByIdIn(idList);
        users.forEach(User::hidePassword);
        return users;
    }

    public Map findApp(Long userId) throws BusinessException {
        Map result = new HashMap();
        App app = new App();
        UserDetail userDetail = userDetailRepository.findById(userId).orElseThrow(() -> new BusinessException("当前用户不存在"));
        List<UserRole> userRoleList = userRoleRepository.findByUserIdAndOrganizationId(userId, userDetail.getCurrentOrganizationId());

        List<Integer> roles = userRoleList.stream().map(UserRole::getRole)
            .collect(Collectors.toList());
        if (roles.contains(2)) {
            app.addProgramTutorApp();
        }
        if (roles.contains(7)) {
            app.addProgramDesignApp();
        }
        if (roles.contains(8)) {
            app.addQuizApp();
        }
        if (roles.contains(9)) {
            app.addUserManagementApp();
            app.addTimerTaskApp();
        }
        if (hasOrganizationRole(userId)) {
            app.addOrganizationApp();
        }

        result.put("data", app.getApps());
        return result;
    }

    private boolean hasOrganizationRole(Long userId) {
        Optional optional = userRoleRepository.findByUserIdAndRole(userId, ORGANIZATION_ROLE);
        return optional.isPresent();
    }

    public void updateUserCurrentOrganization(CreateUserOrganization createUserOrganization) throws BusinessException {
        UserDetail userDetail = userDetailRepository.findById(createUserOrganization.getUserId()).orElseThrow(
            () -> new BusinessException("current user is not exist")
        );
        userDetailRepository.updateCurrentOrganizationId(userDetail.getUserId(), createUserOrganization.getOrganizationId());
    }

    public void modifyUserDetailAndPhone(UserInfo userInfo, Long userId) throws BusinessException {
        UserDetail userDetail = new UserDetail(userId,
            userInfo.getSchool(),
            userInfo.getName(),
            userInfo.getMajor(),
            userInfo.getDegree(),
            userInfo.getGender(),
            userInfo.getSchoolProvince(),
            userInfo.getSchoolCity(),
            userInfo.getEntranceYear(),
            userInfo.getWechat(),
            userInfo.getQq(),
            userInfo.getCurrentOrganizationId());
        userDetailRepository.save(userDetail);
        User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException("当前用户不存在"));
        user.setMobilePhone(userInfo.getMobilePhone());
        userRepository.save(user);
    }

    public List<UserRole> findUserRolesByUserId(Long userId) {
        return userRoleRepository.findAllByUserId(userId);
    }

    @Transactional
    public void importUsers(List<CreateUsersCommand> createUsersCommands) throws BusinessException {
        List<User> users = CreateUsersCommand.buildUsers(createUsersCommands);
        if (verify(users)) {
            users = userRepository.saveAll(users);
            Long organizationId = getOrganizationId(createUsersCommands);
            userDetailRepository.saveAll(UserDetail.buildUsersDetail(users, organizationId));
            addUserOrganizations(users, organizationId);
        }

    }

    private void addUserOrganizations(List<User> users, Long organizationId) {
        List<Long> ids = users.stream()
            .map(User::getId).collect(Collectors.toList());

        organizationCenterFeign.addUsersToOrganization(organizationId, ids);
    }

    private Long getOrganizationId(List<CreateUsersCommand> createUsersCommands) throws BusinessException {
        return Long.parseLong(findUserById(createUsersCommands.get(0).getCreatorId()).get("currentOrganizationId").toString());
    }

    private boolean verify(List<User> users) throws BusinessException {
        List<User> result;
        List<String> userNames = users.stream().map(User::getUsername).collect(Collectors.toList());
        if (!(result = userRepository.findByUsernameIn(userNames)).isEmpty()) {
            throw new BusinessException("导入失败，以下用户的用户名已存在：" +
                result.stream().map(User::getUsername).collect(joining(",")));
        }
        List<String> emails = users.stream().map(User::getEmail).collect(Collectors.toList());
        if (!(result = userRepository.findByEmailIn(emails)).isEmpty()) {
            throw new BusinessException("导入失败，以下用户的邮箱已存在：" +
                result.stream().map(User::getEmail).collect(joining(",")));
        }
        return true;
    }
}